using System;
using System.Text.RegularExpressions;

namespace SecuBat.Crawling.Forms
{
	/// <summary>
	/// Summary description for WebForm.
	/// </summary>
	public class WebForm
	{
		private WebAddress _actionAddress;
		private FormParameterCollection _parameters;
		private FormParameterCollection _buttons;
		private String _encoding = "";
		private FormMethod _method = FormMethod.None;
		private int _id;
		private String _htmlForm;
		private WebAddress _referrer;
		private int _webPageId;
		private int _indexInWebPage;

		public FormParameterCollection Parameters
		{
			get { return _parameters; }
			set { _parameters = value; }
		}

		public FormParameterCollection Buttons
		{
			get { return _buttons; }
			set { _buttons = value; }
		}

		public WebAddress ActionAddress
		{
			get { return _actionAddress; }
			set { _actionAddress = value; }
		}

		public FormMethod Method
		{
			get { return _method; }
			set { _method = value; }
		}

		public string Encoding
		{
			get { return _encoding; }
			set { _encoding = value; }
		}

		public String FormIdentifier
		{
			get
			{
				return this.ActionAddress.Url.ToLower() + ":" + this.Method.ToString().ToUpper();
			}
		}

		public int Id
		{
			get { return _id; }
			set { _id = value; }
		}

		public string HtmlForm
		{
			get { return _htmlForm; }
			set { _htmlForm = value; }
		}

		public WebAddress Referrer
		{
			get { return _referrer; }
			set { _referrer = value; }
		}

		public int WebPageId
		{
			get { return _webPageId; }
			set { _webPageId = value; }
		}

		public int IndexInWebPage
		{
			get { return _indexInWebPage; }
			set { _indexInWebPage = value; }
		}

		private const String _inputExpression = "<\\s*?input\\s.*?type\\s*?=\\s*?([\"']?)([^\\1]*?)\\1(>|\\s.*?>)";
		private const String _actionExpression = "action\\s*?=\\s*?([\"']?)([^\\1]*?)(\\1)([\\s>])";
		private const String _methodExpression = "method\\s*?=\\s*?([\"']?)([^\\1]*?)(\\1)([\\s>])";
		private const String _encodingExpression = "enctype\\s*?=\\s*?([\"']?)([^\\1]*?)(\\1)([\\s>])";


		public WebForm(int id, int webPageId, String htmlForm, WebAddress actionAddress, WebAddress referrer, FormMethod method, String encoding, int indexInWebPage)
		{
			Parameters = new FormParameterCollection();
			Buttons = new FormParameterCollection();
			Id = id;
			HtmlForm = htmlForm;
			Referrer = referrer;
			ActionAddress = actionAddress;
			Method = method;
			Encoding = encoding;
			WebPageId = webPageId;
			IndexInWebPage = indexInWebPage;
		}

		public WebForm(int webPageId, String htmlForm, String htmlAttributeString, WebAddress referrer, int indexInWebPage)
		{
			Parameters = new FormParameterCollection();
			Buttons = new FormParameterCollection();
			Id = -1;
			HtmlForm = htmlForm;
			Referrer = referrer;
			WebPageId = webPageId;
			IndexInWebPage = indexInWebPage;
			ParseAttributes(htmlAttributeString, referrer);
		}

		public void ParseForm()
		{
			this.ParseParameters();
			this.FindButtons();
		}

    private void ParseAttributes(String htmlAttributeString, WebAddress referrer)
		{
			// Extract action address
			Regex actionRegex = new Regex(_actionExpression, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline);
			Match m1 = actionRegex.Match(htmlAttributeString);
			if (m1 != null)
				ActionAddress = new WebAddress(m1.Groups[2].Value, referrer);

			// Extract method
			Regex methodRegex = new Regex(_methodExpression, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline);
			Match m2 = methodRegex.Match(htmlAttributeString);
			if (m2 != null)
			{
				String method = m2.Groups[2].Value;
				if (method.ToLower().Equals("get"))
					Method = FormMethod.Get;
				else
					Method = FormMethod.Post;
			}

			// Extract encoding
			Regex encodingRegex = new Regex(_encodingExpression, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline);
			Match m3 = encodingRegex.Match(htmlAttributeString);
			if (m3 != null)
				Encoding = m3.Groups[2].Value;

		}

		private void ParseParameters()
		{
			// Extract parameters
			Regex inputRegex = new Regex(_inputExpression, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline);
			MatchCollection col = inputRegex.Matches(HtmlForm);
			foreach (Match m4 in col)
			{
				try
				{
					FormParameter p = new FormParameter(m4.Value);
					Parameters.Add(p);
				}
				catch// (Exception ex)
				{
					// Redundand
					//LogManager.Write(TraceLevel.Warning, ex, "Form Parameter parsing");
				}
			}
		}

		private void FindButtons()
		{
			foreach (FormParameter param in this.Parameters)
			{
				if (param.Type.Equals(FormParameterType.Button) || param.Type.Equals(FormParameterType.Submit) ||
					param.Type.Equals(FormParameterType.Image))
					Buttons.Add(param);
			}
		}

		public void Register()
		{
			Id = CrawlDbManager.NewWebForm(WebPageId, this.HtmlForm, this.ActionAddress.Url, this.Referrer.Url, this.Method.ToString(), this.Encoding, DateTime.Now, this.IndexInWebPage);
		}
	}
}
